相信很多讀者都聽過AOP,所以筆者在此就不加贅述了,而裝飾器就是實現AOP的一種編寫程序。簡單解釋裝飾器的功用就是,再不更改程序的狀況下能夠附加功能。在介紹如何實作裝飾器前,先告訴大家如何使用。
本文章同步放置於此
大家先看一下下列例子:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
相信各位讀者對於這例子應該不陌生,沒錯這就是第一天介紹給大家的例子,而裝飾器在哪呢,@app.route("/")
這就是裝飾器,因為有它Python可以寫的更簡潔。
在認識如何使用裝飾器後要介紹大家如何自訂一個裝飾器,請各位讀者看看以下例子:
def printHello(func):
def wrapper():
print('Hello')
return func()
return wrapper
@printHello
def printWorld():
print('World')
printWorld()
如此第一個裝飾器完成了,相信大家應該知道執行後會顯示以下內容:
Hello
World
就這樣我們建立了一個會印出Hello的裝飾器,所以當我們需要一個印出Hello Kitty的函式該如何寫呢?相信許多讀者已經有答案了,如果還沒有想法請看以下例子:
@printHello
def printKitty():
print('Kitty')
printKitty()
裝飾器是怎樣一個語法,為什麼他能夠這樣寫,再來就是他這樣寫是代表甚麼呢?眼尖的讀者可以看到一個特別的符號@
這就是人稱Python@
語法糖的東西,它可以讓你的程序變得簡潔,而@
是代表甚麼呢?請見以下例子:
printWorld = printHello(printWorld)
上述可以說明@
的功用就是將printWorld
丟到printHello
函式中,而我們之前定義printHello
函式就是將丟進來的參數printWorld
包裝後傳出去。所以這邊最外面的printWorld
所接收到的東西就是包裝後的wrapper()
,所以呼叫printWorld
時其實是呼叫wrapper()
所以會先印出Hello
在執行方法printWorld
。相信這樣的解釋可以讓大家對於裝飾器有更進一步的了解。
如果說裝飾器所裝的函式需要輸入參數該如何處理呢,換句話說想要整合printKitty跟printWorld該如何處理呢?相信經過上述的介紹後應該不難處理,不過如果讀者們不知道如何處理請看下列例子吧:
def printHello(func):
def wrapper(arg):
print('Hello')
return func(arg)
return wrapper
@printHello
def printArg(arg):
print(arg)
printArg('World')
printArg('Kitty')
就這樣更進一步的裝飾器完成了,如此裝飾器可以把參數傳達給所定義的函式。
如果裝飾器所掛載的函式參數很複雜時該如何處置呢,總不能定了一堆類似的裝飾器吧。所以這裡介紹一個通吃的參數輸入定義方式,請見以下例子:
def printHello(func):
def wrapper(*args, **kwargs):
print('Hello')
return func(*args, **kwargs)
return wrapper
@printHello
def printSingle(arg):
print(arg)
@printHello
def printDouble(arg1, arg2):
print(arg1)
print(arg2)
printSingle('World')
printDouble('Kitty', 'Danny')
其中*args, **kwargs是甚麼東西啊?請看下列說明。
其中*args
是一個list
指的是不論個數的輸入參數,**kwargs
是一個dict
指的是任何名子的參數,更進一步請看下列說明:
def func(*args, **kwargs):
for item in args:
print("I'm args and value is {0}".format(item))
for key, value in kwargs.items():
print("I'm kwargs and key and value is {0}={1}".format(key, value))
func([{
'name': 10,
'value': 20
}, 1, 2, 3], 12364)
func(name=1023)
結果顯示如下
"I'm args and value is [{'name': 10, 'value': 20}, 1, 2, 3]"
"I'm args and value is 12364"
"I'm kwargs and key and value is name=1023"
透過這兩個參數可以指定所有的輸入參數,如此裝飾器的功能更強大了,能夠用在更多地方了。
處理完掛載的裝飾器之後,如果想要在裝飾器上輸入參數該怎麼辦呢,就看看下列例子吧:
def printArg(arg):
def decorator(func):
def wrapper(*args, **kwargs):
print(arg)
return func(*args, **kwargs)
return wrapper
return decorator
@printArg('Hi')
def sayHiAndPrintArg(arg):
print(arg)
sayHiAndPrintArg('World')
沒想到光一個裝飾器一天還不夠講,明天接續講裝飾器進階的用法,敬請期待。
不知道我的理解有沒有正確
大大範例中
@printHello
def printKitty():
print('Kitty')
printKitty()
意思是 printHello 為printKitty的裝飾器
所以在最後printkitty 時原本只輸出kitty,但也會先呼叫printHello 所以變成‘hellokitty’?
是這樣嗎?
上面的例子是先執行print('hello')在執行print('kitty')所以結果如下
hello
kitty
不知道有沒解決你的問題
不過裝飾器也可以先執行print('kitty'),在執行print('hello')就取決於你裝飾器怎麼實作。
希望有解決到你的問題
哇! 這個裝飾器好玩
我自己也在寫python, 但今天終於知道flask那樣會什麼可以work了~ 裝飾器感覺讓python語法又更活了~